package com.ffmpeg.opt.controller;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.ffmpeg.opt.common.ffmpeg.FmpegUtil;
import com.ffmpeg.opt.common.ffmpeg.handler.MovieTask;
import com.ffmpeg.opt.domain.CallBackResp;
import com.ffmpeg.opt.domain.DurationParam;
import com.ffmpeg.opt.domain.OperationRequestParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 操作fmpeg命令
 */
@RestController
@RequestMapping("/api")
@Slf4j
public class ApiController {

	public static final FmpegUtil fmpegUtil = new FmpegUtil();

	public static final String ffmpeg = "ffmpeg";

	/**
	 * 操作命令
	 */
	@ApiOperation("执行ffmpeg批命令")
	@PostMapping("/operation")
	public ResponseEntity operation(@RequestBody OperationRequestParam param) {
		long startTime  = System.currentTimeMillis();
		boolean success = true;
		try {
			OperationRequestParam.CommandDesc[] commands = param.getCommands();
			// 1.拿到命令先获取时长
			DurationParam durationParam = new DurationParam();
			durationParam.setResourcePath(param.getResourcePath());
			durationParam.setTaskId(param.getTaskId());
			Long duration = duration(durationParam).getBody();
			// 2.时长获取后，走其他命令
			for (int i = 0, j = 1; i < commands.length; i++, j++) {
				log.info("步骤{}：开始", j);
				OperationRequestParam.CommandDesc commandDesc = commands[i];
				executeCommond(param.getTaskId(), "[ "+param.getTaskDesc()+" ]步骤" + j + "："+commandDesc.getName(),commandDesc.getCommand(), duration);
				log.info("步骤{}：结束", j);
				ThreadUtil.sleep(500);
			}
		}catch (Exception e){
			log.error(ExceptionUtil.stacktraceToString(e));
			success = false;
		}finally {
			// 3.回调
			long endTime  = System.currentTimeMillis();
			String callBackUrl = param.getCallBackUrl();
			if(StrUtil.isNotBlank(callBackUrl)){
				CallBackResp callBackResp = new CallBackResp();
				callBackResp.setExt(param.getExt());
				callBackResp.setTaskId(param.getTaskId());
				callBackResp.setTime(endTime-startTime);
				callBackResp.setSuccess(success);
				String post = HttpUtil.post(callBackUrl, JSONUtil.toJsonStr(callBackResp));
				log.info("回调结果:{}",post);
			}
		}
		return ResponseEntity.ok().build();
	}

	/**
	 * 查询任务进度
	 */
	@ApiOperation("查询批命令的执行进度")
	@GetMapping("/query/{taskIds}")
	public ResponseEntity<Map<String,String>> query(@PathVariable String[] taskIds) {
		Map<String,String> result = new HashMap<>();
		for (String taskId : taskIds) {
			result.put(taskId, fmpegUtil.queryProgress(taskId));
		}
		return ResponseEntity.ok(result);
	}

	/**
	 * 默认回调结果，测试用
	 */
	@PostMapping("/callback")
	public ResponseEntity<String> callbackDefault(@RequestBody String json) {
		log.info("成功处理回调结果:{}",json);
		return ResponseEntity.ok(json);
	}

	/**
	 * 获取视频时长
	 */
	@ApiOperation("查询视频的时长")
	@GetMapping("/duration")
	public ResponseEntity<Long> duration(DurationParam param) {
		long startTime  = System.currentTimeMillis();
		log.info("获取视频时长");
		String commond = ffmpeg + " -i " + param.getResourcePath();
		MovieTask build = MovieTask.build(param.getTaskId(), "初始：获取时长", null);
		fmpegUtil.start(commond, build);
		Long duration = null;
		while (duration == null) {
			duration = build.getDuration();
			log.info("正在获取时长....");
			ThreadUtil.sleep(1000);
		}
		log.info("获取视频时长结束：{}", duration);
		fmpegUtil.waitDone(param.getTaskId());
		ThreadUtil.sleep(500);
		fmpegUtil.stop(param.getTaskId());
		// 3.回调
		long endTime  = System.currentTimeMillis();
		String callBackUrl = param.getCallBackUrl();
		if(StrUtil.isNotBlank(callBackUrl)){
			CallBackResp callBackResp = new CallBackResp();
			callBackResp.setExt(param.getExt());
			callBackResp.setTaskId(param.getTaskId());
			callBackResp.setTime(endTime-startTime);
			callBackResp.setSuccess(true);
			String post = HttpUtil.post(callBackUrl, JSONUtil.toJsonStr(callBackResp));
			log.info("回调结果:{}",post);
		}
		return ResponseEntity.ok(duration);
	}

	/**
	 * 执行命令
	 *
	 * @param taskId   任务ID
	 * @param taskDesc 任务描述
	 * @param commond  命令
	 * @param duration 时长
	 */
	public void executeCommond(String taskId, String taskDesc, String commond, Long duration) {
		log.info(taskDesc + "开始");
		MovieTask build = MovieTask.build(taskId, taskDesc, duration);
		fmpegUtil.start(commond, build);
		fmpegUtil.waitDone(taskId);
		ThreadUtil.sleep(500);
		fmpegUtil.stop(taskId);
		log.info(taskDesc + "结束");
	}

}
